package com.cmict.data.infra.service.message;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cmict.data.bpm.api.task.BpmTaskApi;
import com.cmict.data.bpm.api.task.dto.BpmTaskExtDTO;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.common.util.date.DateUtils;
import com.cmict.data.framework.tenant.core.aop.TenantIgnore;
import com.cmict.data.infra.api.emus.NotifySendTypeEnum;
import com.cmict.data.infra.controller.admin.message.vo.AnnouncementDTO;
import com.cmict.data.infra.controller.admin.message.vo.AnnouncementPageVO;
import com.cmict.data.infra.controller.admin.message.vo.AnnouncementQO;
import com.cmict.data.infra.controller.admin.message.vo.NotifyInfo;
import com.cmict.data.infra.convert.message.AnnouncementConverter;
import com.cmict.data.infra.convert.message.NotifyInfoConverter;
import com.cmict.data.infra.dal.dataobject.message.Announcement;
import com.cmict.data.infra.dal.dataobject.message.UserAnnouncement;
import com.cmict.data.infra.dal.mysql.message.AnnouncementMapper;
import com.cmict.data.infra.dal.mysql.message.UserAnnouncementMapper;
import com.cmict.data.infra.enums.message.AnnouncementStatusEnum;
import com.cmict.data.infra.enums.message.ErrorCodeConstants;
import com.cmict.data.infra.push.NotifyPushExecutor;
import com.cmict.data.infra.recipient.RecipientHandler;
import com.cmict.data.infra.service.message.job.ScheduledMessageService;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.infra.enums.message.ErrorCodeConstants.TIME_BIGGER_NOW;

/**
 * 公告信息
 *
 * @author hccake 2020-12-15 17:01:15
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Announcement>
        implements AnnouncementService {

    private final NotifyPushExecutor notifyPushExecutor;

    private final UserAnnouncementMapper userAnnouncementMapper;

    private final ScheduledMessageService scheduledMessageService;

    private final RecipientHandler recipientHandler;

    private final AdminUserApi adminUserApi;

    private final BpmTaskApi taskApi;

    /**
     * 根据QueryObject查询分页数据
     *
     * @param qo 查询参数对象
     * @return PageResult<AnnouncementVO> 分页数据
     */
    @Override
    public PageResult<AnnouncementPageVO> queryPage(AnnouncementQO qo) {
        PageResult<Announcement> pageResult = baseMapper.queryPage(qo);
        PageResult<AnnouncementPageVO> result = new PageResult<>();
        BeanUtils.copyProperties(pageResult, result);
        List<AnnouncementPageVO> list = new ArrayList<>();
        pageResult.getList().forEach(announcement -> {
            AnnouncementPageVO pageVO = new AnnouncementPageVO();
            BeanUtils.copyProperties(announcement, pageVO);
            JSONArray array = recipientHandler.filterInfo(announcement.getRecipientFilterType(), announcement.getRecipientFilterCondition());
            pageVO.setRecipientFilterCondition(array);
//            LocalDateTime time =  baseMapper.selectMaxTime("select GREATEST(create_time,ifnull(update_time,0),ifnull(send_time,0)) from `notify_announcement`  where  id  =   "+announcement.getId());
//            pageVO.setCreateTime(time);
            list.add(pageVO);
        });
        return result.setList(list);
    }

    /**
     * 创建公告
     *
     * @param announcementDTO 公告信息
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addAnnouncement(AnnouncementDTO announcementDTO) {
        Announcement announcement = AnnouncementConverter.INSTANCE.dtoToPo(announcementDTO);
        announcement.setStatus(AnnouncementStatusEnum.UNPUBLISHED.getValue());
        announcement.setId(null);
        announcement.setAllFileList(announcementDTO.getAllFileList());
        int flag = baseMapper.insert(announcement);
        boolean inserted = SqlHelper.retBool(flag);
        // 公告发布事件
        if (inserted && announcement.getSendAction() != NotifySendTypeEnum.DRAFT.getValue()) {
            this.sendAnnouncement(announcement);
        }
        return inserted;
    }

    /**
     * 更新公告信息
     *
     * @param announcementDTO announcementDTO
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAnnouncement(AnnouncementDTO announcementDTO) {
        Announcement oldAnnouncement = baseMapper.selectById(announcementDTO.getId());
        if (oldAnnouncement.getStatus() == AnnouncementStatusEnum.PUBLISHED.getValue()) {
            throw exception(ErrorCodeConstants.NOTICE_CANNOT_UPDATE);
        }

        Announcement announcement = AnnouncementConverter.INSTANCE.dtoToPo(announcementDTO);

        // 保证当前状态未被修改过
        boolean isUpdated = baseMapper.updateIfUnpublished(announcement);

        if (isUpdated && announcement.getSendAction() != NotifySendTypeEnum.DRAFT.getValue()) {
            //以前是未发送，现在发送，正常通知
            this.sendAnnouncement(announcement);
        }
        return isUpdated;
    }


    /**
     * 获取用户拉取过的发布中，且满足失效时间的公告信息
     *
     * @param userId 用户id
     * @return List<Announcement>
     */
    @Override
    public List<Announcement> listActiveAnnouncements(Long userId) {
        return baseMapper.listUserAnnouncements(userId);
    }

    /**
     * 删除公告
     *
     * @param id
     * @return
     */
    @Override
    public boolean removeId(Long id) {
        int i = baseMapper.deleteById(id);
        //清理掉所有该公告的关联关系
        if (userAnnouncementMapper.selectCount(UserAnnouncement::getAnnouncementId, id) > 0) {
            QueryWrapper<UserAnnouncement> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(UserAnnouncement::getAnnouncementId, id);
            userAnnouncementMapper.delete(queryWrapper);
        }
        return SqlHelper.retBool(i);
    }


    /**
     * 撤回公告
     *
     * @param id
     * @return
     */
    @Override
    public boolean retractId(Long id) {
        Announcement announcement = baseMapper.selectById(id);
        announcement.setStatus(AnnouncementStatusEnum.RETRACT.getValue());
        int i = baseMapper.updateById(announcement);
        //清理掉所有该公告的关联关系
        if (userAnnouncementMapper.selectCount(UserAnnouncement::getAnnouncementId, id) > 0) {
//            QueryWrapper<UserAnnouncement> queryWrapper = new QueryWrapper<>();
//            queryWrapper.lambda().eq(UserAnnouncement::getAnnouncementId, id);
            userAnnouncementMapper.deleteByAnnouncementId(id);
        }
        return SqlHelper.retBool(i);
    }

    /**
     * 定时发送公告
     *
     * @param id
     */
    @Override
    @TenantIgnore
    public void sendAnnouncement(Long id) {
        Announcement announcement = baseMapper.selectById(id);
        if (announcement == null) {
            throw exception(ErrorCodeConstants.NOTICE_NOT_FOUND);
        }
            //超时发送
        if(announcement.getIsRemind()!= null && announcement.getIsRemind()){
            announcement.setStatus(AnnouncementStatusEnum.UNPUBLISHED.getValue());
            Announcement announcementRemind = new Announcement();
            BeanUtils.copyProperties(announcement,announcementRemind);
            announcementRemind.setId(null);
            announcementRemind.setStatus(AnnouncementStatusEnum.UNPUBLISHED.getValue());
            announcementRemind.setCompleterFrequency(announcement.getCompleterFrequency() + 1);
            baseMapper.insert(announcementRemind);
            Long lastId =    baseMapper.getLAST_INSERT_ID();
            // 是否开启 流程 超时发送
            if(announcementRemind.getIsRemind() != null && announcementRemind.getIsRemind() && announcementRemind.getFrequency() >= announcementRemind.getCompleterFrequency() ){
                BpmTaskExtDTO bpmTaskExtDO =  taskApi.getTaskExt(announcementRemind.getRemindId()).getCheckedData(); //数据状态 result  待审核  status 正常
                if(bpmTaskExtDO != null ){
                    LocalDateTime sendTime = LocalDateTimeUtil.offset(bpmTaskExtDO.getCreateTime(),  announcementRemind.getTime().multiply(new BigDecimal(60)).intValue() + announcement.getMessage().multiply(new BigDecimal(announcement.getCompleterFrequency().toString())).multiply(new BigDecimal(60)).intValue(), ChronoUnit.MINUTES) ;

                    scheduledMessageService.addJob(lastId, sendTime);
                }
            }
        }
        if (announcement.getStatus() != AnnouncementStatusEnum.PUBLISHED.getValue()) {
            if(announcement.getFrequency() !=null && announcement.getFrequency() == announcement.getCompleterFrequency()){
                announcement.setIsRemind(false);
            }
            onAnnouncementPublish(announcement);
            announcement.setStatus(AnnouncementStatusEnum.PUBLISHED.getValue());
            baseMapper.updateById(announcement);
        }
    }

    /**
     * 发送公告
     *
     * @param announcement
     */
    private void sendAnnouncement(Announcement announcement) {
        if (scheduledMessageService.checkExists(announcement.getId())) {
            scheduledMessageService.deleteJob(announcement.getId());
        }
        if (announcement.getSendAction() == NotifySendTypeEnum.SEND_NOW.getValue()) {
            //立即发送
            onAnnouncementPublish(announcement);
            // 是否开启 流程 超时发送
            if(announcement.getIsRemind() != null && announcement.getIsRemind() && announcement.getFrequency() >= announcement.getCompleterFrequency() ){
//                 BpmTaskExtDO bpmTaskExtDO =  baseMapper.getBpmtaskext(announcement.getRemindId());
//                if(bpmTaskExtDO != null ){
                LocalDateTime sendTime = LocalDateTimeUtil.offset(LocalDateTime.now(),  announcement.getTime().multiply(new BigDecimal(60)).intValue(), ChronoUnit.MINUTES) ;
                scheduledMessageService.addJob(announcement.getId(), sendTime);
//                }
            }

        } else {
            //定时发送
            if (announcement.getSendTime() != null && DateUtils.of(announcement.getSendTime()).getTime() < new Date().getTime()) {
                throw exception(TIME_BIGGER_NOW);
            }
            scheduledMessageService.addJob(announcement.getId(), announcement.getSendTime());
        }

    }


    /**
     * 公告发布事件
     *
     * @param announcement 公告信息
     */
    private void onAnnouncementPublish(Announcement announcement) {
        NotifyInfo notifyInfo = NotifyInfoConverter.INSTANCE.fromAnnouncement(announcement);
        notifyPushExecutor.push(notifyInfo);
    }


    public Announcement getAnnouncement(Long id) {
        Announcement announcement = baseMapper.selectById(id);
        announcement.setRecipientFilterCondition(null);
        AdminUserRespDTO user = StringUtil.isBlank(announcement.getCreator()) ? null : adminUserApi.getUser(Long.valueOf(announcement.getCreator())).getCheckedData();
        announcement.setUsername(user != null ? user.getUsername() : "用户已删除");
        return announcement;
    }

}
